/*
 * Filename: g:\espidf_workspace\idf_S3_T-Watch\main\audio\audio_player.cc
 * Path: g:\espidf_workspace\idf_S3_T-Watch\main\audio
 * Created Date: Monday, June 23rd 2025, 11:18:34 am
 * Author: sss
 *
 * Copyright (c) 2025 Your Company
 */

#include "audio_player.h"
#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "driver/i2s.h"
#include "driver/i2s_types.h"
#include "driver/i2s_std.h"

#include "mp3_codec.h"

static const char *TAG = "AUDIO_PLAYER";


esp_err_t mp3player_event_handler(esp_http_client_event_t *evt)
{
    static char *output_buffer;  // Buffer to store response of http request from event handler
    static int output_len;       // Stores number of bytes read
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            // Clean the buffer in case of a new request
            // printf(evt->data);
            // ESP_LOGI(TAG, "%s" , (char*)evt->data);

            MP3_CODEC& mp3_codec = MP3_CODEC::get_instance();
            uint8_t output_buffer = (char*)malloc(1024 * 1024);
            size_t output_len = 0;
            mp3_codec.decode_mp3_to_pcm((void*)evt->data, evt->data_len, &output_buffer, &output_len)

            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
            
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            break;
        case HTTP_EVENT_REDIRECT:
            ESP_LOGI(TAG, "HTTP_EVENT_REDIRECT");
            break;
    }
    return ESP_OK;
}


/**
 * 初始化 i2s
 */
void AUDIO_PLAYER::init_i2s()
{
    if (i2s_inited)
    {
        return NULL;
    }
    ESP_LOGI("AUDIO_PLAYER", "init_i2s");
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_TX,
        .sample_rate = 44100,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 8,
        .dma_buf_len = 64,
        .use_apll = false,
        .tx_desc_auto_clear = true,
        .fixed_mclk = 0};
    i2s_pin_config_t pin_config = {
        .bck_io_num = AUDIO_PLAYER_IIS_BCK,
        .ws_io_num = AUDIO_PLAYER_IIS_WS,
        .data_out_num = AUDIO_PLAYER_IIS_DOUT,
        .mck_io_num = I2S_PIN_NO_CHANGE};
    esp_err_t ret = i2s_driver_install(AUDIO_PLAYER_PORT, &i2s_config, 0, NULL);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "i2s_driver_install error");
        return;
    }
    ret = i2s_set_pin(AUDIO_PLAYER_PORT, &pin_config);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "i2s_set_pin error");
        return;
    }
    i2s_inited = true;
    // 创建环形 buffer
    buf_handle = xRingbufferCreate(sizeof(uint8_t) * ring_buffer_size, RINGBUF_TYPE_NOSPLIT);
    if (buf_handle == NULL)
    {
        ESP_LOGE(TAG, "xRingbufferCreate error");
        deinit_i2s(); // 释放i2s资源
        return;
    }
}
/**
 *
 */
void AUDIO_PLAYER::deinit_i2s()
{
    if (!i2s_inited)
    {
        return NULL;
    }
    ESP_LOGI("AUDIO_PLAYER", "deinit_i2s");
    i2s_driver_uninstall(AUDIO_PLAYER_PORT);

    clear_buffer();
    vRingbufferDelete(buf_handle);//free ring buffer
    i2s_inited = false;
}
void AUDIO_PLAYER::clear_buffer(){
    if (buf_handle == NULL)
    {
        return;
    }
    size_t item_size;
    void *item;
    while ((item = xRingbufferReceive(buf_handle, &item_size, 0)) {//清空环形buffer
        vRingbufferReturnItem(buf_handle, item);
    }
}

void AUDIO_PLAYER::play()
{
    init_i2s();
    // 从不可分割环形 buffer 中接收一个数据项
    if (buf_handle == NULL)
    {
        /* code */
        ESP_LOGE(TAG, "ring buffer is null");
        return;
    }

    size_t item_size;

    while (playing)
    {
        /* code */

        uint8_t *item = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000));
        // Check received item
        if (item != NULL)
        {
            // Print item
            //  for (int i = 0; i < item_size; i++) {
            //      printf("%c", item[i]);
            //  }
            //  printf("\n");
            // 返回数据项
            // 播放数据项
            size_t i2s_write_bytes = 0;
            esp_err_t ret = i2s_write(AUDIO_PLAYER_PORT, item, item_size * 2, &i2s_write_bytes, 100 / portTICK_RATE_MS);
            if (ret != ESP_OK)
            {
                ESP_LOGE(TAG, "i2s_write error");
            }
            vRingbufferReturnItem(buf_handle, (void *)item); // 释放
        }
        else
        {
            // 数据项检索失败
            ESP_LOGE(TAG, "Failed to receive item");
            vTaskDelay(pdMS_TO_TICKS(300));
        }
    }
}

void AUDIO_PLAYER::play_url(const char *audio_url)
{
    init_i2s();
    // TODO: implement this function
}

size_t AUDIO_PLAYER::push_audio_data(void *data, size_t len)
{
    init_i2s();
    if (buf_handle == NULL)
    {
        return 0;
    }

    size_t free_size = xRingbufferGetCurFreeSize(buf_handle);

    if (free_size < len)
    {
        ESP_LOGE(TAG, "ring buffer is full");
        return 0;
    }

    if (xRingbufferSend(buf_handle, data, len, 100 / portTICK_RATE_MS) != pdTRUE)
    {
        ESP_LOGE(TAG, "xRingbufferSend error");
    }
    // TODO: implement this function
    // 发送数据到ringbuffer中 开始播放
    return len;
}

void AUDIO_PLAYER::stop_audio()
{
    // TODO: implement this function
    // 清除ringbuffer中的数据 停止播放

    playing = false;
    deinit_i2s();
}

void AUDIO_PLAYER::pause_audio()
{
    // TODO: implement this function
    playing = false;
}

void AUDIO_PLAYER::resume_audio()
{
    // TODO: implement this function
    playing = true;
}

AUDIO_PLAYER::AUDIO_PLAYER()
{
}

AUDIO_PLAYER::~AUDIO_PLAYER()
{
}